package com.nb.ds.datasource;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.lang.reflect.Method;

/**
 * @author lihaoyang6
 * @date 2024年04月21日 17:50
 */
@Slf4j
@Component
@Aspect
public class DynamicDataSourceAspect {

    /**
     * @annotation：这个表达式的含义是匹配所有带有特定注解的方法。
     *          例如，@annotation(com.foo.MyAnnotation)将匹配所有带有@MyAnnotation注解的方法。
     * @within：这个表达式的含义是匹配所有在特定注解的类中的方法，不管这个方法本身有没有这个注解。
     *          例如，@within(com.foo.MyAnnotation)将匹配所有在带有@MyAnnotation注解的类中的方法。
     */
    @Pointcut("@annotation(com.nb.ds.datasource.DS) " +
            "|| @within(com.nb.ds.datasource.DS)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Class targetClass = point.getTarget().getClass();
        Method method = signature.getMethod();

        DS targetDataSource = (DS)targetClass.getAnnotation(DS.class);
        DS methodDataSource = method.getAnnotation(DS.class);
        if(targetDataSource != null || methodDataSource != null){
            String value;
            if(methodDataSource != null){
                //优先用方法上的
                value = methodDataSource.value();
            }else {
                //类上的
                value = targetDataSource.value();
            }
            DynamicDataSource.setDataSource(value);
            log.debug("set datasource is {}", value);
        }

        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            log.debug("clean datasource");
        }
    }


}
